﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Dispatcher;
using System.ComponentModel.Composition;
using System.Net;
using System.Net.Http;
using Bzure.Mvc.Controllers;
using Bzure.Common.Composition;
using Bzure.Common.Core;

namespace Bzure.Mvc.Controllers
{
    public class ThemeHttpControllerSelector : DefaultHttpControllerSelector
    {
        class ControllerContainer : MEFContainerBase
        {
            [ImportMany]
            public IEnumerable<Lazy<IHttpController, IHttpControllerMetadata>> ControllerFactories;
        }
        ControllerContainer ControllerBox;
        private const string NamespaceRouteVariableName = "Namespace";
        private readonly HttpConfiguration _configuration;
        private readonly Lazy<ConcurrentDictionary<string, Type>> _apiControllerCache;

        public ThemeHttpControllerSelector(HttpConfiguration configuration)
            : base(configuration)
        {
            ControllerBox = new ControllerContainer();
            ControllerBox.Compose();
            _configuration = configuration;
            _apiControllerCache = new Lazy<ConcurrentDictionary<string, Type>>(new Func<ConcurrentDictionary<string, Type>>(InitializeApiControllerCache));
        }

        private ConcurrentDictionary<string, Type> InitializeApiControllerCache()
        {
            //IAssembliesResolver assembliesResolver = this._configuration.Services.GetAssembliesResolver();
            //var types = this._configuration.Services.GetHttpControllerTypeResolver().GetControllerTypes(assembliesResolver).ToDictionary(t => t.FullName, t => t);
            var types = this.ControllerBox.ControllerFactories.ToDictionary(t => t.Metadata.Name.ToLower(), t => t.Metadata.Type);

            return new ConcurrentDictionary<string, Type>(types);
        }
        public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
        {
            Type type;
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }
            string controllerName = this.GetControllerName(request);
            if (string.IsNullOrEmpty(controllerName))
            {
                throw new HttpResponseException(request.CreateErrorResponse(HttpStatusCode.NotFound,
                    string.Format("No route providing a controller name was found to match request URI '{0}'", new object[] { request.RequestUri })));
            }
            //IEnumerable<string> fullNames = GetControllerFullName(request, controllerName);
            //if (fullNames.Count() == 0)
            //{
            //    throw new HttpResponseException(request.CreateErrorResponse(HttpStatusCode.NotFound,
            //            string.Format("No route providing a controller name was found to match request URI '{0}'", new object[] { request.RequestUri })));
            //}
            if (this._apiControllerCache.Value.TryGetValue(controllerName.ToLower(), out type))
            {
                return new HttpControllerDescriptor(_configuration, controllerName, type);
            }
            throw new HttpResponseException(request.CreateErrorResponse(HttpStatusCode.NotFound,
                string.Format("No route providing a controller name was found to match request URI '{0}'", new object[] { request.RequestUri })));
        }
    }
}
